/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package prvydevw.servlet;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.xml.sax.SAXException;

/**
 *
 * @author kuba
 */
public class ExportServlet extends HttpServlet {
    
    private static final String DOCBOOK_JSTL = "/export.jsp";
    private static final String FOP_TRANSFORMATION = "/transform/fopTrans.xsl";
    private static final String FONT_FAMILY = "DejaVuSerif, 'Times New Roman', serif";

   
    
    /* Wrapper for getting output generated from JSTL */
    private class ToStringResponseWrapper extends HttpServletResponseWrapper {
        private final StringWriter sw = new StringWriter();

        public ToStringResponseWrapper(HttpServletResponse response){
            super(response);
        }
        @Override
        public PrintWriter getWriter() throws IOException {
            return new PrintWriter(sw);
        }
        
        @Override
        public String toString() {
            return sw.toString();
        }
    };
    
    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException, TransformerException, ConfigurationException, FOPException, SAXException{
        if (request.getAttribute("exportType").equals("pdf")){
            exportPdf(request, response);
        }
        else{
            exportDocbook(response, request);
        }
    }
    
     private void exportDocbook(HttpServletResponse response, HttpServletRequest request) throws IOException, ServletException {
        HttpServletResponseWrapper responseWrapper = new ToStringResponseWrapper(response);
        BufferedOutputStream outs = null;
        InputStream docbookArrayStream = null;
        try{
            request.getRequestDispatcher(DOCBOOK_JSTL).include(request, responseWrapper);
            String docbookString = responseWrapper.toString();
          
            docbookArrayStream = new ByteArrayInputStream( docbookString.getBytes(Charset.forName("UTF-8")));
            
            response.setContentType("application/xml");
            response.setHeader("Content-Disposition","attachment;filename=prvydevw-export.xml");
            
            outs = new BufferedOutputStream(response.getOutputStream());
            int len;
            byte[] buf = new byte[1024];
            while ((len = docbookArrayStream.read(buf)) > 0) {
                outs.write(buf, 0, len);
            }
        } finally{
            if (docbookArrayStream != null){
                docbookArrayStream.close();
            }
            if (outs != null){
                outs.close();
            }
        }
    }
    
     private void exportPdf(HttpServletRequest request, HttpServletResponse response ) throws IOException, TransformerException, ConfigurationException, FOPException, SAXException, ServletException{
         
         HttpServletResponseWrapper responseWrapper = new ToStringResponseWrapper(response);
         ByteArrayOutputStream arrayStream = null;
         InputStream docbookArrayStream = null;
         try{
             request.getRequestDispatcher(DOCBOOK_JSTL).include(request, responseWrapper);
             String docbookString = responseWrapper.toString();
             
             
             docbookArrayStream = new ByteArrayInputStream( docbookString.getBytes(Charset.forName("UTF-8")));
             System.setProperty("javax.xml.transform.TransformerFactory",
                     "net.sf.saxon.TransformerFactoryImpl");
             arrayStream = new ByteArrayOutputStream();
             
             URL fopTrans = this.getClass().getResource(FOP_TRANSFORMATION);
             transfromDocbookToPdf(docbookArrayStream, fopTrans, arrayStream);
             
             // to write the content to out put stream
             byte[] pdfBytes = arrayStream.toByteArray();
             response.setContentLength(pdfBytes.length);
             response.setContentType("application/pdf");
             response.addHeader("Content-Disposition",
                     "attachment;filename=prvydevw-export.pdf");
             response.getOutputStream().write(pdfBytes);
             response.getOutputStream().flush();
         }      
         finally{
             if (docbookArrayStream != null){
                 docbookArrayStream.close();
             }
             if (arrayStream != null){
                 arrayStream.close();
             }
         }
     }
    
    private void transfromDocbookToPdf(InputStream sourceStream, URL xsltURL, OutputStream os) throws IOException, TransformerException, ConfigurationException, FOPException, SAXException {
        InputStream fopStream = null;
        DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder();
        Configuration cfg = null;
        StreamSource sourceXmlStream = null;
        StreamSource xlsStream = null;
        InputStream urlStream = null;
        try {
            fopStream = getClass().getClassLoader().getResourceAsStream("fop.xconf");
            cfg = cfgBuilder.build(fopStream);
            FopFactory fopFactory = FopFactory.newInstance();
            fopFactory.setUserConfig(cfg);
            FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
            TransformerFactory tFactory = TransformerFactory.newInstance();
            
            
            Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, os);
            
            
            urlStream = xsltURL.openStream();
            xlsStream = new StreamSource(urlStream, xsltURL.toExternalForm());
            Transformer transformer = tFactory.newTransformer(xlsStream);
            transformer.setParameter("generate.toc", "nop");
            transformer.setParameter("body.font.family", FONT_FAMILY);
            transformer.setParameter("title.font.family", FONT_FAMILY);
            Result res = new SAXResult(fop.getDefaultHandler());
            
            sourceXmlStream = new StreamSource(sourceStream);
            transformer.transform(sourceXmlStream, res);

        } finally{
            if (fopStream != null){
                fopStream.close();
            }
            if (urlStream != null){
                urlStream.close();
            }
        }
    }
    
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (TransformerException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot transform file", ex);
        } catch (ConfigurationException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot use configuration file", ex);
        } catch (FOPException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot convert file to fop", ex);
        } catch (SAXException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot parse file", ex);
        }
    }
    
    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (TransformerException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot transform file", ex);
        } catch (ConfigurationException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot use configuration file", ex);
        } catch (FOPException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot convert file to fop", ex);
        } catch (SAXException ex) {
            Logger.getLogger(ExportServlet.class.getName()).log(Level.SEVERE, null, ex);
            throw new ServletException("Cannot parse file", ex);
        }
    }
    
    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
